package com.woniuxy.auctionSystem.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.woniuxy.auctionSystem.entity.User;
import com.woniuxy.auctionSystem.mapper.UserMapper;
import com.woniuxy.common.dto.user.UserLoginDto;
import com.woniuxy.common.dto.user.UserRegistDto;
import com.woniuxy.common.enums.RedisConstant;
import com.woniuxy.common.exceptions.Assert;
import com.woniuxy.common.result.enums.impl.BusinessCode;
import com.woniuxy.common.utils.JwtUtils;
import com.woniuxy.common.vo.UserLoginVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {
    @Autowired
    UserMapper userMapper;
    @Autowired
    JwtUtils jwtUtils;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    TransactionTemplate transactionTemplate;
    /**
     * 用户注册
     * @param userRegistDto
     */
    @Transactional  //默认抛出 RuntimeException  就回滚
    public void regiter(UserRegistDto userRegistDto) {
        //userRegistDto.getPhone().intern()  可以防止 想通的手机 获得锁
        //synchronized (userRegistDto.getPhone().intern()){
        //begin
        //1. 验证手机号 是否被注册过
        Long count = userMapper.isExitPhone(userRegistDto.getPhone());
        //commit
        //断言判断  手机好是否被注册过
        Assert.error(count > 0, BusinessCode.PHONE_EXISTED);

        //2.保存用户信息
        saveUserInfo(userRegistDto);
        //}
    }
    //保存用户信息
    private void saveUserInfo(UserRegistDto userRegistDto) {
        //创建一个User 对象
        User user = new User();
        user.setPhone(userRegistDto.getPhone());
        user.setUsername(userRegistDto.getUserName());
        user.setPassword(userRegistDto.getPwd());
        userMapper.insert(user);
    }

    public UserLoginVo login(UserLoginDto userLoginDto) {
        //判断是什么登录
        boolean phoneLogin = userLoginDto.isPhoneLogin();

       /* if (phoneLogin) {
            return  phoneLogin(userLoginDto.getLoginName(),userLoginDto.getLoginSecret());
        }else {
            return uplogin(userLoginDto.getLoginName(),userLoginDto.getLoginSecret());
        }*/
        return phoneLogin == true ? phoneLogin(userLoginDto.getLoginName(),userLoginDto.getLoginSecret())
                : uplogin(userLoginDto.getLoginName(),userLoginDto.getLoginSecret());
    }



    //账号登录
    private UserLoginVo uplogin(String loginName, String loginSecret) {
        // 1.根据用户名 查询 用户信息
        User user = userMapper.selectUserByName(loginName);
        //判断 user 是否为空
        Assert.error(user,BusinessCode.USER_NOT_EXIST);
        //判断密码是否正确
        Assert.error(!loginSecret.equals(user.getPassword()),BusinessCode.LOGIN_FAIL);

        //封装返回值
        return getLoginVo(user);
    }

    private UserLoginVo getLoginVo(User user) {
        UserLoginVo userLoginVo = BeanUtil.copyProperties(user,UserLoginVo.class);
        //生成 token  存储到 UserLoginVo 对象
        Map<String,Object> maps = new HashMap<>();
        maps.put("id",user.getId());
        maps.put("userName",user.getUsername());
        maps.put("phone",user.getPhone());

        String token = jwtUtils.createToken(maps);
        userLoginVo.setToken(token);

        ////把token存储到redis中(用来做token续期)
        stringRedisTemplate.opsForValue().set(
                RedisConstant.USER_TOKEN+user.getId(), token, 30, TimeUnit.MINUTES);

        return userLoginVo;
    }

    /**
     * isPhoneLogin为false，表示根据用户名密码登录
     * 实现：校验用户名密码是否存在
     * isPhoneLogin为true，表示根据手机号验证码登录
     * 实现：
     *      1、访问短信验证码接口，实现验证码发送 （sddfp-oss）
     *      2、校验验证码：获取redis中的验证码与用户输入的验证码对比
     *      3、手机号不存在自动注册功能：随机生成6位用户名、密码默认
     *      4、手机号存在则返回
     */
    private UserLoginVo phoneLogin(String phone, String code) {
        //查询一下验证码
        String redisCode = stringRedisTemplate.opsForValue().get(RedisConstant.REDIS_SMS_PREFIX+phone);
        //判断验证码是否村粗在
        Assert.error(redisCode,BusinessCode.USER_VERIFY_CODE_ERROR);
        // 查看验证码是否错误
        Assert.error(!redisCode.equals(code),BusinessCode.USER_VERIFY_CODE_ERROR);
        //1. 验证 手机号是否注册过
        User user = userMapper.selectUserByPhone(phone);
        if (user == null){
            //没有注册过
            UserRegistDto userRegistDto = new UserRegistDto();
            userRegistDto.setPhone(phone);
            userRegistDto.setPwd("123456");
            userRegistDto.setUserName(RandomUtil.randomString(6));

            //注册 处理局部事务
            transactionTemplate.execute((status -> {
                this.regiter(userRegistDto);
                return new Object();
            }));

            //查询一次
            user = userMapper.selectUserByPhone(phone);
        }

        UserLoginVo loginVo = getLoginVo(user);
        //删除验证码
        stringRedisTemplate.delete(RedisConstant.REDIS_SMS_PREFIX+phone);
        return loginVo;
    }
}
